﻿using System.Collections.Generic;
using System.IO;

namespace TPOJ.Core
{
    /// <summary>
    /// The Comparer of the judge engine.
    /// </summary>
    class Comparer
    {
        public string CorrectAnswerPath { get; set; }
        public string UserAnswerPath { get; set; }
        public List<string> PERules { get; set; }

        /// <summary>
        /// Create a Comparer.
        /// </summary>
        /// <param name="correctAnswerPath">Correct answer path</param>
        /// <param name="userAnswerPath">User program answer path</param>
        /// <param name="PERulesPath">Rules path for Presentation Error</param>
        public Comparer(string correctAnswerPath, string userAnswerPath, string PERulesPath = null)
        {
            this.CorrectAnswerPath = correctAnswerPath;
            this.UserAnswerPath = userAnswerPath;
            GetPERules(PERulesPath);
        }

        /// <summary>
        /// Get Presentation Error Rules.
        /// </summary>
        /// <param name="PERulesPath">PE rules file path</param>
        private void GetPERules(string PERulesPath)
        {
            if(string.IsNullOrEmpty(PERulesPath))
                return;

            string rules;
            string[] rulesArray;
            using (StreamReader sr = new StreamReader(PERulesPath))
            {
                rules = sr.ReadToEnd().Trim();
            }
            rulesArray = rules.Split('|');
            foreach (var item in rulesArray)
            {
                if (!string.IsNullOrEmpty(item))
                    this.PERules.Add(item);
            }
        }

        /// <summary>
        /// Do the comparation.
        /// </summary>
        /// <returns>The comparing result</returns>
        public Result Compare()
        {
            string correct, user;
            Result result = new Result();

            try
            {
                using (StreamReader sr = new StreamReader(this.CorrectAnswerPath))
                {
                    correct = sr.ReadToEnd();
                }
                using (StreamReader sr = new StreamReader(this.UserAnswerPath))
                {
                    user = sr.ReadToEnd();
                }
            }
            catch (FileNotFoundException)
            {
                result.ExitCode = -1;
                result.ResultType = ResultType.SystemError;
                result.ErrorMessage = "System error";
                return result;
            }
            
            if (user.CompareTo(correct) == 0)
            {
                result.ResultType = ResultType.Accepted;
                return result;
            }
            else
            {
                if (TrimAll(user).CompareTo(TrimAll(correct)) == 0)
                {
                    result.ResultType = ResultType.RepresentationError;
                    return result;
                }
            }
            result.ResultType = ResultType.WrongAnswer;
            return result;
        }

        /// <summary>
        /// Get the output data without decoration.
        /// </summary>
        /// <param name="source">User program output</param>
        /// <returns>Essential output</returns>
        private string TrimAll(string source)
        {
            string[] whiteSpaces = { "\f", "\n", "\r", "\t", "\v", "\x85", " " };
            source.Trim();
            if (this.PERules != null)
            {
                foreach (var item in this.PERules)
                {
                    source = source.Replace(item, "");
                }
            }

            foreach (var item in whiteSpaces)
            {
                source = source.Replace(item, "");
            }
            return source;
        }
    }
}
